import java.io.File;
import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class IO {

	// Socket de comunicacao do roteador, e o seu id
	private DatagramSocket socket;

	/**
	 * Recupera o modelo a partir dos arquivos de configuracao.
	 *
	 * @throws Exception
	 *             caso falhe a entrada dos arquivos
	 */
	/**
	 * Atualiza o modelo de acordo com os arquivos de configuracao.
	 *
	 * @param modelo
	 * @throws Exception
	 *             caso falhe a entrada dos arquivos
	 */
	public static void lerArquivos(Modelo modelo) throws Exception {
		int id = modelo.getId();

		Map<Integer, Link> idOfLinks = new HashMap<Integer, Link>();

		// Le o arquivo de configuracao do roteador
		Scanner routerCfg = new Scanner(new FileInputStream(new File(
				"roteador.config")));
		while (routerCfg.hasNextLine()) {
			String[] line = routerCfg.nextLine().trim().split("\\s+");

			int tId = Integer.parseInt(line[0]);
			int tPort = Integer.parseInt(line[1]);
			String tAddress = line[2];

			if (tId == id) {
				modelo.setPort(tPort);
			} else {
				modelo.addRoteador(tId);
				idOfLinks.put(tId, new Link(-1, tPort, tAddress));
			}
		}
		routerCfg.close();

		// Le o arquivo dos enlaces
		Scanner linkCfg = new Scanner(new FileInputStream(new File(
				"enlaces.config")));
		while (linkCfg.hasNextLine()) {
			String[] line = linkCfg.nextLine().trim().split("\\s+");

			int idA = Integer.parseInt(line[0]);
			int idB = Integer.parseInt(line[1]);
			int cost = Integer.parseInt(line[2]);

			// Caso A seja meu roteador, adiciono B como vizinho
			if (idA == id) {
				Link tL = idOfLinks.get(idB);

				Link toAdd = new Link(cost, tL.getPort(), tL.getIp()
						.getHostAddress());
				modelo.addEnlace(idB, toAdd);
			}

			// Caso B seja meu roteador, adiciono A como vizinho
			if (idB == id) {
				Link tL = idOfLinks.get(idA);

				Link toAdd = new Link(cost, tL.getPort(), tL.getIp()
						.getHostAddress());
				modelo.addEnlace(idA, toAdd);
			}

		}
		linkCfg.close();
	}

	/**
	 * Recupera a mensagem repassada por outro roteador.
	 *
	 * @return A mensagem recebida.
	 * @throws Exception
	 *             caso o socket falhe ao receber o pacote.
	 */
	public String getMessage() throws Exception {
		byte[] receiveData = new byte[1024];
		DatagramPacket receivePacket = new DatagramPacket(receiveData,
				receiveData.length);

		this.socket.receive(receivePacket);

		return new String(receivePacket.getData()).trim();
	}

	/**
	 * Envia uma mensagem para outro roteador.
	 *
	 * @param enlace
	 *            enlace para o qual a mensagem sera enviada.
	 * @param message
	 *            mensagem a ser enviada.
	 * @throws Exception
	 *             caso o pacote nao possa ser enviado.
	 */
	public void sendMessage(Link enlace, String message) throws Exception {
		byte[] sendData = message.getBytes();
		
		DatagramPacket packet = new DatagramPacket(sendData, sendData.length,
				enlace.getIp(), enlace.getPort());
		this.socket.send(packet);
	}

	/**
	 * Cria o socket de comunicacao do roteador.
	 *
	 * @param port
	 *            porta utilizada pelo socket.
	 * @throws Exception
	 *             caso o socket nao possa ser criado.
	 */
	public void createSocket(int port) throws Exception {
		this.socket = new DatagramSocket(port);
	}

}
